#include <pthread.h>
#include <unistd.h>

#include "sql.h"
#include "log.h"
#include "core_conf.h"
#include "task.h"
#include "task_manager.h"
#include "db.h"

extern struct core_conf core_conf;
static int sql_server_gone_away(unsigned int errno);

void sql_init(void)
{
	log_info("begin sql_init.");

	pthread_t tid = pthread_self();
	struct task *task = get_task_by_tid(tid);
	if (task == NULL) {
		log_error("no such task.");
		return;
	}

	/* TODO:lock task when you add remove-task feature. */
	task->db_ops = get_db_ops(); 
	if (task->db_ops == NULL) {
		log_error("cann't get db");
		/* TODO: I don't know what I should do now... */
		while (1) {
			log_print("cann't get db");
			sleep(100);
		}
		return;
	}

	task->db_ops->task = task;
}

int sql_query(char *command)
{
	log_info("begin sql_query.");

	pthread_t tid = pthread_self();
	struct task *task = get_task_by_tid(tid);
	if (task == NULL) {
		log_error("no such task.");
		return 65535;
	}


	int ret = 0;
	ret = task->db_ops->sql_query(task->db_ops, command);
	
	if (ret != 0) {
		unsigned int sql_err_number = sql_errorno();

		if (sql_server_gone_away(sql_err_number)) {
			log_error("sql_server_gone_away.");
			/* TODO: Here we can use sql_init() because our arithmetic use ref-count, so we are sure we can select a new sql. */
			sql_init();
			ret = sql_query(command);
		}
	}
	
	return ret;
}

static int sql_server_gone_away(unsigned int errno)
{
	log_info("begin sql_server_gone_away.");

	pthread_t tid = pthread_self();
	struct task *task = get_task_by_tid(tid);
	if (task == NULL) {
		log_error("no such task.");
		return 65535;
	}

	return task->db_ops->sql_server_gone_away(task->db_ops, errno);
}

unsigned int sql_errorno(void)
{
	log_info("begin sql_errorno.");

	pthread_t tid = pthread_self();
	struct task *task = get_task_by_tid(tid);
	if (task == NULL) {
		log_error("no such task.");
		return 65535;
	}

	return task->db_ops->sql_errorno(task->db_ops);
}

const char *sql_error(void)
{
	log_info("begin sql_error.");

	pthread_t tid = pthread_self();
	struct task *task = get_task_by_tid(tid);
	if (task == NULL) {
		log_error("no such task.");
		return "<no such task>";
	}
	
	return task->db_ops->sql_error(task->db_ops);
}
